package com.ht.circuitbreaker.start;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

public class CircuitBreaker {
    int fail;
    int all;
    int failTime;
    int interval;
    volatile boolean isBreaker = false;
    FailBack failBack;
    private AtomicInteger processFail = new AtomicInteger(0);
    private AtomicInteger processing = new AtomicInteger(0);
    private DelayQueue<MyDelayedTask> queueProcessing = new DelayQueue();
    private DelayQueue<MyDelayedTask> queueProcessFail = new DelayQueue();
    private Object brock = new Object();
    Thread breakerThread = null;
    FailBack callback = null;
    public CircuitBreaker(){
        this(10, 50, 10, 5, new FailBack() {
            @Override
            public void callback(Object obj) {
                System.out.println(obj);
            }
        });
    }

    /**
     *
     * @param fail 失败数
     * @param all 总请求数
     * @Param interval 上面的请求所在的时间间隔内
     * failTime 失败时间
     * @param callback
     */
    public CircuitBreaker(int fail, int all, int interval,int failTime, FailBack callback){
        this.fail = fail;
        this.all =all;
        this.failBack = callback;
        this.interval = interval * 1000;
        this.failTime = failTime * 1000;
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(startDelayQueue(queueProcessing));
        executorService.submit(startDelayQueue(queueProcessFail));
        startBreaker();
    }

    public void run(TargetFun targetFun){
        if (!check()) {
            breaker();
            if (callback != null) {
                callback.callback("失败");
            }
            return;
        }
        MyDelayedTask task = new MyDelayedTask("",interval);
        queueProcessing.offer(task);
        try {
            targetFun.handler();
        } catch (Throwable t) {
            queueProcessFail.offer(task);
        }
    }

    private void breaker(){
        if (isBreaker) {
            return;
        }
        isBreaker = true;
        LockSupport.unpark(breakerThread);
    }

    private boolean check(){
        if (isBreaker) {
            failBack.callback("breaker");
            return false;
        }
        if (queueProcessing.size() > all) {
            failBack.callback("queue full");
            return false;
        }
        if (queueProcessFail.size() > fail) {
            failBack.callback("fail full");
            return false;
        }
        return true;
    }

    private Runnable startDelayQueue(DelayQueue queue){
        return new Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        queue.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    }

    private void startBreaker(){
        breakerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (!isBreaker) {
                        LockSupport.park();
                    }
                    System.out.println("开始断路恢复");
                    try {
                        Thread.sleep(failTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    queueProcessFail.clear();
                    queueProcessing.clear();
                    isBreaker = false;
                    System.out.println("恢复成功");
                }
            }
        });
        breakerThread.start();
    }
}
